#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <mpi.h>
#include <time.h>
#include<ctype.h>
#define MAX 100
#define num_threads 7//lSize divisel por 7

char arruma(char letra);
int palindromo(char string[]);


int main(int argc, char ** argv) {
FILE * pFile;
long lSize;
char * buffer[num_threads];
size_t result;
int contador_frase = 0, contador_palavra = 0;
int i = 0, j = 0, k = 0;
clock_t inicio = 0, fim = 0;
/////////    variáveis para MPI	//////////////
	int ret, numTasks, myRank;
	int intIN, intOUT, intIN2, intOUT2;  //intIN e intOUT : variáveis auxiliares para contar frases que são palíndromos.
					    //intIN2 e intOUT2 : variáveis auxiliares para contar palavras que são palíndromos
	MPI_Status stat;
	
	srand(time(NULL));
	
	ret = MPI_Init(&argc, &argv);
	if(ret != MPI_SUCCESS)
		exit(1);
	
	MPI_Comm_size(MPI_COMM_WORLD, &numTasks);
	MPI_Comm_rank(MPI_COMM_WORLD, &myRank);

inicio = clock();		//inicia a contagem do tempo

pFile = fopen ( "shakespe.txt" , "r+" );
if (pFile==NULL) {fputs ("File error",stderr); exit (1);}

// tamanho do arquivo
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
int TAM = lSize/num_threads;
rewind (pFile);

// aloca os blocos com tamanho lSize/num_threads
for(i = 0; i < num_threads; i++){
buffer[i] = (char*) malloc (sizeof(char)*TAM);
}

// copia para o buffer
for(i = 0; i < num_threads; i++){
result = fread (buffer[i],1,TAM,pFile);
if (result != TAM) {
    fputs ("Reading error",stderr); exit (3);}
}

/* the whole file is now loaded in the memory buffer. */

char frase[100000], palavra[100000]; //variaveis para armazenar frase e palavra e o processo pai enviá-las para os filhos.
int a = 0;

while(i < strlen(buffer[k])) {
while(buffer[k][i] != '\r' && buffer[k][i] != '.') {
    if(isalpha(buffer[k][i])){//verifica se é alfanumerico, se for palavra recebe o caracter
       palavra[a] = buffer[k][i];
       a++;
    }
    else{
        palavra[a] = '\0';
        a = 0;
	if(myRank == 0){  //se é processo pai
		MPI_Send(&palavra, 100000, MPI_CHAR, 1, 0, MPI_COMM_WORLD); //envia a palavra para o filho 1
		MPI_Recv(&intIN2, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &stat); //recebe para saber se a palavra enviada é palindromo
		contador_palavra += intIN2;	//soma ao contador_palavra 1 se for palindromo e 0 se não for.

	}
	else if(myRank == 1){ //se é o processo filho de rank 1
	MPI_Recv(&palavra, 100000, MPI_CHAR, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); //recebe a palavra
	intOUT2 = 0;	//variavel auxiliar inicia com valor 0
        if(palindromo(palavra) == 0 && strlen(palavra) > 3){		//e confere se é palindromo
		intOUT2 = 1; //se for palindromo a variavel auxiliar recebe valor 1
        }
		MPI_Send(&intOUT2, 1, MPI_INT, 0, 1, MPI_COMM_WORLD); //variavel auxiliar é enviada ao processo pai.
	}
    }
frase[j] = buffer[k][i];
 j++;
  i++;
}
frase[j] = '\0';
j = 0;

if(myRank == 0)  //terminada de ler a frase, se é o processo pai
{
MPI_Send(&frase, 100000, MPI_CHAR, 2, 0, MPI_COMM_WORLD); //envia a frase ao filho de rank 2
MPI_Recv(&intIN, 1, MPI_INT, 2, 1, MPI_COMM_WORLD, &stat);  //espera o filho "dizer" se a frase é ou não palindromo.
contador_frase += intIN;  //soma 1 se for e 0 se nao for ao contador de frases
}
if(myRank == 2){  //se é o filho de rank 2
MPI_Recv(&frase, 100000, MPI_CHAR, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);  //recebe a frase
intOUT = 0;  //variavel auxiliar inicia com valor 0
if(palindromo(frase) == 0 && strlen(frase) > 3) {
intOUT = 1; //se a frase for palindromo, a variavel auxiliar recebe valor 1
}
MPI_Send(&intOUT, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);  //e então, a variavel auxiliar é enviada ao processo pai.
}
i++;
}


fim  = clock();
//tempo de execução
double  tempo = (fim - inicio)/(CLOCKS_PER_SEC/1000);


if(myRank == 0)
{
printf("\nTotal de frases palindromos: %d", contador_frase);
printf("\nTotal de palavras palindromos: %d", contador_palavra);
printf("\nTempo de execução : %g", tempo);
}

MPI_Finalize(); //finaliza mpi
// terminate
fclose (pFile);

for(i = 0; i < num_threads; i++){
free (buffer[i]);
}




return 0;
}

int palindromo(char string[]) {

char strcomespaco[MAX],str1[MAX], str2[MAX];
int tamcomespaco,tam, i, j;

strcpy(strcomespaco,string);

tamcomespaco = strlen(strcomespaco);

for(i=0,j=0;i<tamcomespaco;i++) {
strcomespaco[i] = arruma(strcomespaco[i]);
if(isalpha(strcomespaco[i])) {
str1[j] = strcomespaco[i];
j++;
}
}

str1[j]='\0';

tam = strlen(str1);

for (i=tam-1,j=0;i>=0;i--,j++){
str2[j] = str1[i];
if(str2[j] != str1[j])
return 1;
}

str2[tam] = '\0';


return 0;
}

char arruma(char letra) {
if(letra >= 65 && letra <= 90)
letra = letra + 32;

return letra;
}